package fundamental;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

import static fundamental.Params.*;
import static initialization.InitialFunction.*;
import static localSearch.LocalSearch.*;

public class Check {
    /**
     * 检测二级路径中是否每个点都被访问，且车辆装载量是否合适，cand的服务能力是否合适
     */
    public static void check2() {
        HashMap<Cand, Integer> candLoad = new HashMap<>();
        for (SecondVehicle v: secondVehicleList
             ) {
            int loading = 0;
            int totalLoad = 0;
            for (Point p: v.route
                 ) {
                if (p instanceof Customer) {
                    loading += ((Customer)p).demand;
                    totalLoad += ((Customer)p).demand+((Customer)p).overDemand;
                }
            }
            Cand cand = ((Cand)v.route.get(0));
            candLoad.put(cand, candLoad.getOrDefault(cand, 0)+totalLoad);
            if (v.loading != loading) {
                System.out.println("车辆装载量计算出来的是"+v.loading+",实际上应该是"+loading);
                throw new RuntimeException();
            }
        }
        for (Cand cand: candLoad.keySet()
             ) {
            if (cand.loading + cand.overLoading != candLoad.get(cand)) {
                System.out.println(cand+"计算出来的loading是"+cand.loading+"，实际上是"+candLoad.get(cand));
                throw new RuntimeException();
            }
        }
    }

    /**
     * 检测一级路径中是否每个点都被访问，且车辆装载量是否合适
     */
    public static void check1() {
        for (FirstVehicle v: firstVehicleList
             ) {
            //System.out.println(v.route);
            int loading = 0;
            for (Point p: v.route
                 ) {
                if (p instanceof Cand) {
                    loading += ((Cand)p).loading;
                }
            }
            if (v.loading != loading) {
                System.out.println("车辆装载量计算出来的是"+v.loading+",实际上应该是"+loading);
                throw new RuntimeException();
            }
        }
    }

    /**
     * 检验开放的cand数量
     */
    public static void checkOpenedCand() {
        HashSet<Cand> cands1 = new HashSet<>();
        ArrayList<Cand> cands2 = new ArrayList<>();
        for (FirstVehicle v: firstVehicleList
        ) {
            //System.out.println(v.route);
            for (Point p: v.route
            ) {
                if (p instanceof Cand) {
                    cands1.add((Cand) p);
                    cands2.add((Cand) p);
                }
            }
        }
        HashSet<Cand> cands3 = new HashSet<>();
        for (SecondVehicle v: secondVehicleList
             ) {
            cands3.add(v.start_end);
        }
        if (cands1.size() != cands2.size() || cands1.size() != openedCandSet.size()) {
            System.out.println("开放的备选点数量不对");
            System.out.println("实际开放的数量"+openedCandSet.size());
            System.out.println("计算开放的数量"+cands1.size());
            System.out.println("计算开放的数量"+cands2.size());
            throw  new RuntimeException();
        }
        if (!cands3.equals(cands1)) {
            System.out.println("第一级和第二级路径中的cand不一致");
            throw new RuntimeException();
        }
    }

    /**
     * 检测一级路径中是否每一条路径最多串两个
     */
    public static void checkVehicle1() {
        for (FirstVehicle v: firstVehicleList
             ) {
            if (v.route.size() > 4) {
                System.out.println(v.route);
                throw new RuntimeException();
            }
        }
    }

    /**
     * 检验成本是否一致
     */
    public static void checkCost2() {
        double sec = getSecCost();
        if (Math.abs(sec - secCost) > tolerance) {
            System.out.println("成本不匹配");
            System.out.println("实际的二级成本为："+sec);
            System.out.println("计算的二级成本为："+secCost);
            throw new RuntimeException();
        }
    }

    public static void checkCost1() {
        double fir = getFirCost();
        if (Math.abs(fir - firCost) > tolerance) {
            System.out.println("成本不匹配");
            System.out.println("实际的一级成本为："+fir);
            System.out.println("计算的一级成本为："+firCost);
            throw new RuntimeException();
        }
    }

    /**
     * 检测移除了same点的tour是否有漏点
     */
    public static void checkGiantValidTour() {
        int n = giantTSP.validTour.size();
        HashSet<Point> temp = new HashSet<>(giantTSP.validTour);
        for (Cand cand: openedCandSet
             ) {
            temp.add(cand.sameCust);
        }
        if (temp.size() != custNum || n + openedCandSet.size() != custNum) {
            System.out.println("tour中数量不对");
            System.out.println("tour中有"+n+"个数");
            System.out.println("openedCand有"+openedCandSet.size()+"个");
            System.out.println("两个合起来有"+temp.size()+"个");
            throw new RuntimeException("");
        }
    }

    /**
     * 检查客户总需求和网点的总需求是否一致
     */
    public static void checkTotalDemand() {
        int totalDemand = 0;
        for (Customer cust: custSet
             ) {
            totalDemand += cust.demand+cust.overDemand;
        }
        int openedDemand = 0;
        int closedDemand = 0;
        for (Cand cand: candSet
             ) {
            if (openedCandSet.contains(cand)) openedDemand += cand.loading + cand.overLoading;
            else closedDemand += cand.loading + cand.overLoading;
        }
        if (openedDemand != totalDemand) {
            System.out.println("实际的需求为："+totalDemand);
            System.out.println("计算的需求为："+openedDemand);
            throw new RuntimeException();
        }
        if (closedDemand != 0) {
            System.out.println("未开放cand的需求不为0");
            throw new RuntimeException();
        }
    }

    public static void checkBestCost() {
        for (Cand c: candList
             ) {
            c.initial();
        }
        openedCandSet.clear();
        double secTravelCost = 0;
        double openCost;
        double secVFCost = 0;
        double firTravelCost = 0;
        double firVFCost = 0;
        double totalCost;
        int secVNum = 0;
        int totalDemand = 0;
        for (Customer cust: custSet
             ) {
            totalDemand += cust.demand + cust.overDemand;
        }
        for (SecondVehicle v: lsObj.secVehicleList
             ) {
            if (v.route.size() == 2) continue;
            if (!(v.route.size() == 3 && v.start_end.sameCust == v.route.get(1))) secVNum += 1;

            openedCandSet.add(v.start_end);
            for (int i = 0; i < v.route.size()-1; i++) {
                Point p1 = v.route.get(i);
                Point p2 = v.route.get(i+1);
                secTravelCost += dist[p1.num][p2.num]*vvar2;
                secVFCost += vFix2;
                if (p2 instanceof Customer) {
                    Customer c = (Customer) p2;
                    v.start_end.loading += c.demand+c.overDemand;
                    secVNum += c.overDemand/cap2;
                    secTravelCost += (dist[c.num][v.start_end.num]*2*vvar2)*(double)(c.overDemand/cap2);
                    secVFCost += (double)(c.overDemand/cap2)*vFix2;
                }
            }
        }
        for (Cand cand: openedCandSet
             ) {
            cand.flashLoading(cap1);

        }
        for (FirstVehicle v: lsObj.firVehicleList
             ) {
            if (v.route.size() == 2) continue;
            firVFCost += vFix1;
            for (int i = 0; i < v.route.size()-1; i++) {
                Point p1 = v.route.get(i);
                Point p2 = v.route.get(i+1);
                firTravelCost += dist[p1.num][p2.num]*vvar1;
                if (p2 instanceof Cand) {
                    Cand c = (Cand) p2;
                    firTravelCost += (dist[c.num][v.start_end.num]*2*vvar1)*(double)(c.overLoading/cap1);
                    firVFCost += (double)(c.overLoading/cap1)*vFix1;
                }
            }
        }
        openCost = openedCandSet.size() * cFix;
        totalCost = secTravelCost+secVFCost+openCost+firTravelCost+firVFCost;
        if (Math.abs(totalCost - lsObj.cost) > tolerance) {
            System.out.println("成本核实不对");
            System.out.println("实际成本为："+totalCost);
            System.out.println("计算成本为："+lsObj.cost);
            System.out.println("secTravelCost="+secTravelCost);
            System.out.println("secVFCost="+secVFCost);
            System.out.println("openCost="+openCost);
            System.out.println("firTravelCost="+firTravelCost);
            System.out.println("firVFCost="+firVFCost);
            System.out.println("lsObj.firCost="+lsObj.firCost);
            System.out.println("lsObj.secCost="+lsObj.secCost);
            throw new RuntimeException();
        }else {
            System.out.println("成本为："+totalCost);
            System.out.println("C型车的行驶成本="+secTravelCost);
            System.out.println("C型车的固定成本="+secVFCost);
            System.out.println("C型车的数量="+secVNum);
            System.out.println("开放的网点的成本="+openCost);
            System.out.println("A型车的行驶成本="+firTravelCost);
            System.out.println("A型车的固定成本="+firVFCost);
            System.out.println("顾客总需求="+totalDemand);
        }
    }
}
